////////////////////////////////////////////////////////////////////////////////
/// @file    spi.c
/// @author  AE TEAM
/// @brief    In window comparator mode,The transformation results are detected
///           Set the threshold value from 0 to 3V, and connect PB6 and PA0 with
///           jumper cap to see the effect.
////////////////////////////////////////////////////////////////////////////////
/// @attention
///
/// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE
/// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE
/// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR
/// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH
/// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN
/// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS.
///
/// <H2><CENTER>&COPY; COPYRIGHT MINDMOTION </CENTER></H2>
////////////////////////////////////////////////////////////////////////////////
// Define to prevent recursive inclusion
#define _SPI_C_

// Files includes
#include "delay.h"
#include "uart.h"
#include "spi.h"

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup MM32_Hardware_Abstract_Layer
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup SPI
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @brief  Turn off the data transmission direction of SPI in bidirectional mode
/// @note   None.
/// @param  SPIx:SPI1/SPI2.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPIM_TXEn(SPI_TypeDef* SPIx)
{
    //Transmit Enable bit TXEN
    SPI_BiDirectionalLineConfig(SPIx, SPI_Direction_Tx);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Turn off the data transmission direction of SPI in bidirectional mode
/// @note   None.
/// @param  SPIx:SPI1/SPI2.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPIM_RXEn(SPI_TypeDef* SPIx)
{
    //enable RXEN
    SPI_BiDirectionalLineConfig(SPIx, SPI_Direction_Rx);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Reset internal NSS pins for selected SPI software
/// @note   None.
/// @param  None.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPIM_CSLow()
{
    //Spi cs assign to this pin,select
    SPI_CSInternalSelected(SPI, ENABLE);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Reset internal NSS pins for selected SPI software
/// @note   None.
/// @param  None.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPIM_CSHigh()
{
    //Spi cs release
    SPI_CSInternalSelected(SPI, DISABLE);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Initializes the SPIx peripheral according to the specified
///         parameters in the SPI_InitStruct
/// @note   None.
/// @param  SPIx: where x can be 0, 1 to select the SPI peripheral.
/// @param  SPI_InitStruct: pointer to a SPI_InitTypeDef structure that
///         contains the configuration information for the specified
///         SPI peripheral.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_Initxbit(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct)
{
    u32 tmpreg = 0;


    //---------------------------- SPIx GCTL Configuration ---------------------
    // Get the SPIx GCTL value
    tmpreg = SPIx->GCR;
    // Clear csn_sel, dmamode, txtlf, rxtlf,data_sel, rxen, txen, mm, int_en, spien bits
    tmpreg &= ((u16)0xF000);
    //Configure SPIx: direction, NSS management, first transmitted bit,
    //BaudRate prescalermaster/salve mode, CPOL and CPHA
    //Set dat_sel bits according to SPI_DataSize value
    //Set csn and csn_sel bits according to SPI_NSS value
    //Set mm bit according to SPI_Mode value */
    tmpreg |= (u32)((u32)SPI_InitStruct->SPI_DataSize | SPI_InitStruct->SPI_NSS |
                    SPI_InitStruct->SPI_Mode);
    // Write to SPIx GCTL
    SPIx->GCR = tmpreg;
    //---------------------------- SPIx CCTL Configuration ---------------------
    tmpreg = SPIx->GCR;
    // Clear spilen, lsbfe, CPOL, CPHA bits
    tmpreg &= ((u16)0xFFC0);
    // Set Spilen bit according to SPI_DataWidth value
    // Set LSBFirst bit according to SPI_FirstBit value
    // Set CPOL bit according to SPI_CPOL value
    // Set CPHA bit according to SPI_CPHA value
    tmpreg |= ((u32)SPI_InitStruct->SPI_FirstBit | (u32)SPI_InitStruct->SPI_CPOL |
               (u32)SPI_InitStruct->SPI_CPHA);

    // Write to SPIx CCTL
    SPIx->GCR = tmpreg | 0x18;

    //---------------------------- SPIx SPBRG Configuration ------------------
    tmpreg = SPIx->BRR;
    // Clear spbrg bits
    tmpreg &= (u16)((u16)0x0000);
    // Set BR bits according to SPI_BaudRatePrescaler value
    tmpreg |= (u16)SPI_InitStruct->SPI_BaudRatePrescaler;
    // Write to SPIx SPBRG
    SPIx->BRR = tmpreg;

//    if ((SPI_InitStruct->SPI_DataWidth) != SPI_DataWidth_8b) {
//        SPIx->CCTL |= 1 << 2; //lsbfe
    SPIx->CCR |= 1 << 3; //spilen
//    }
    SPIx->ECR = SPI_InitStruct->SPI_DataWidth;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Modifiable parameter initialization SPI.
/// @note   None.
/// @param  SPIx:SPI1/SPI2.
/// @param  spi_baud_div:Specifies the Baud Rate prescaler value which will be.
/// @param  datawidth:data byte length.
/// @param  mode    :SPI mode.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPIM_Initxbit(SPI_TypeDef* SPIx, u16 spi_baud_div)
{
    SPI_InitTypeDef SPI_InitStructure;
    GPIO_InitTypeDef  GPIO_InitStructure;
    //NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1RSTR_SPI1, ENABLE);
    SPIM_CSHigh();

    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
    //spi2_cs  pb12
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin  = SPI_NSS_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(SPI_NSS_PORT, &GPIO_InitStructure);
    //spi2_sck  pb13
    GPIO_InitStructure.GPIO_Pin  = SPI_SCK_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(SPI_SCK_PORT, &GPIO_InitStructure);
    //spi2_mosi  pb15
    GPIO_InitStructure.GPIO_Pin  = SPI_MOSI_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(SPI_MOSI_PORT, &GPIO_InitStructure);
    //spi2_miso  pb14
    GPIO_InitStructure.GPIO_Pin  = SPI_MISO_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(SPI_MISO_PORT, &GPIO_InitStructure);

    GPIO_PinAFConfig(SPI_MOSI_PORT, SPI_MOSI_AFSOURCE, SPI_MOSI_AFMODE);
    GPIO_PinAFConfig(SPI_NSS_PORT, SPI_NSS_AFSOURCE, SPI_NSS_AFMODE);
    GPIO_PinAFConfig(SPI_MISO_PORT, SPI_MISO_AFSOURCE, SPI_MISO_AFMODE);
    GPIO_PinAFConfig(SPI_SCK_PORT, SPI_SCK_AFSOURCE, SPI_SCK_AFMODE);

    SPI_StructInit(&SPI_InitStructure);
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_DataWidth = SPI_DataWidth_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = (SPI_BaudRatePrescaler_TypeDef)spi_baud_div;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_Init(SPIx, &SPI_InitStructure);

    SPI_Cmd(SPIx, ENABLE);
    SPIM_TXEn(SPIx);
    SPIM_RXEn(SPIx);
}




u32 Reverse32Bit(u32 n)
{
    n = (n & 0x55555555) << 1 | (n & 0xAAAAAAAA) >> 1;
    n = (n & 0x33333333) << 2 | (n & 0xCCCCCCCC) >> 2;
    n = (n & 0x0F0F0F0F) << 4 | (n & 0xF0F0F0F0) >> 4;
    n = (n & 0x00FF00FF) << 8 | (n & 0xFF00FF00) >> 8;
    n = (n & 0x0000FFFF) << 16 | (n & 0xFFFF0000) >> 16;
    return n;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Transmits a Data through the SPIx peripheral.
/// @note   None.
/// @param  SPIx: SPI1/SPI2
/// @param  Data : Data to be transmitted.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void SPI_Send_1_32bits(SPI_TypeDef* SPIx, u32 SendData)
{
    u8 temp = 0;
    u8* puChars;

    puChars = (u8*) &SendData;

    // Write in the TXREG register the data to be sent
    temp = SPIx->ECR;
    temp = temp & 0x1F;
#ifndef SPIUSELSB
    // use MSB
    if(temp == 0) {
        temp = 32;
    }
    else {
        SendData = SendData << (32 - temp);
    }

#ifdef USECORTEX_M3
    SendData = __rbit(SendData);
#else
    SendData = Reverse32Bit(SendData);
#endif


#endif
    // use LSB
    if(temp == 0) {
        temp = 32;
    }
    if(temp <= 8) {
        SPIx->TDR = puChars[0];
    }
    else if(temp <= 16) {
        SPIx->TDR = puChars[0];
        SPIx->TDR = puChars[1];
    }
    else if(temp <= 24) {
        SPIx->TDR = puChars[0];
        SPIx->TDR = puChars[1];
        SPIx->TDR = puChars[2];
    }
    else {
        SPIx->TDR = puChars[0];
        SPIx->TDR = puChars[1];
        SPIx->TDR = puChars[2];
        SPIx->TDR = puChars[3];
    }

}

////////////////////////////////////////////////////////////////////////////////
/// @brief   Returns the most recent received data by the SPIx peripheral.
/// @note    None.
/// @param   SPIx: SPI1/SPI2
/// @retval  The value of the received data.
////////////////////////////////////////////////////////////////////////////////
u32 SPI_Recv_1_32bits(SPI_TypeDef* SPIx)
{
    u8 temp = 0;
    u32 RecvData = 0;
    u8* puChars;

    puChars = (u8*) &RecvData;

    temp = SPIx->ECR;
    if(temp == 0) {
        temp = 32;
    }
    // use LSB
    if(temp <= 8) {
        puChars[0] = (u8)SPIx->RDR;
    }
    else if(temp <= 16) {
        puChars[0] = (u8)SPIx->RDR;
        puChars[1] = (u8)SPIx->RDR;
    }
    else if(temp <= 24) {
        puChars[0] = (u8)SPIx->RDR;
        puChars[1] = (u8)SPIx->RDR;
        puChars[2] = (u8)SPIx->RDR;
    }
    else {
        puChars[0] = (u8)SPIx->RDR;
        puChars[1] = (u8)SPIx->RDR;
        puChars[2] = (u8)SPIx->RDR;
        puChars[3] = (u8)SPIx->RDR;
    }
#ifndef SPIUSELSB
    // use MSB
#ifdef USECORTEX_M3
    SendData = __rbit(SendData);
#else
    RecvData = Reverse32Bit(RecvData);
#endif
    RecvData = RecvData >> (32 - temp);
#endif
    return RecvData;
}


////////////////////////////////////////////////////////////////////////////////
/// @brief   Transmit and receive data through peripheral SPIx for full duplex mode.
/// @note    None.
/// @param   SPIx: SPI1/SPI2
/// @param   tx_data:send data.
/// @retval  None.
////////////////////////////////////////////////////////////////////////////////
u32 SPIMWriteRead_1_32bits(SPI_TypeDef* SPIx, u32 tx_data)
{
    u32 rx_data;
    SPI_Send_1_32bits(SPIx, tx_data);
    while (1) {
        if(SPI_GetFlagStatus(SPIx, SPI_FLAG_TXEPT)) {
            break;
        }
    }

    while (1) {
        if(SPI_GetFlagStatus(SPIx, SPI_FLAG_RXAVL)) {
            rx_data = SPI_Recv_1_32bits(SPIx);
            break;
        }
    }
    return rx_data;
}

u8 tx_data[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
u8 rx_data[10];

////////////////////////////////////////////////////////////////////////////////
/// @brief   Transceiver/Receiver Test.
/// @note    None.
/// @param   None.
/// @retval  None.
////////////////////////////////////////////////////////////////////////////////
void SPI_1_32bit_Test(void)
{
    u32 t;
    SPIM_CSLow();
    for(t = 0; t < 10; t++) {
        rx_data[t] = SPIMWriteRead_1_32bits(SPI, tx_data[t]);
        printf("rx[%d]=0x%x\r\n", t, rx_data[t]);
    }
    SPIM_CSHigh();
    printf("SPI2 test over\r\n");
}

/// @}

/// @}

/// @}
